//Copyright (c) 2008, Matthew Newman
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
//* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
//* Neither the name of BestSnowman.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Globalization;
using ProductKeyManager.UI;
using System.Data.SqlServerCe;
using ProductKeyManager.DB;
using System.Resources;
using Bindable.Linq;
using LiveLabs.Logging.Logs;
using LiveLabs.Logging;

namespace ProductKeyManager
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public sealed partial class MainWindow : System.Windows.Window, IDisposable
    {
        DB.ProductKeyManagerDataContext db;
        LiveLabs.Logging.Log logger;
        internal static string logFile = "pkmlog.log";
        internal static string dbFile = "pkmdb3.sdf";

        private string searchText;
        private SortDirection nameSort = SortDirection.None;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
// If we are in debug mode we want to use a different DB file to prevent
// potential issues with an installed release version
#if DEBUG
            MainWindow.logFile = "pkmlog-debug.log";
            MainWindow.dbFile  = "pkmdb3-debug.sdf";
            Properties.Settings.Default.ConnectionString = string.Empty;
#endif

            LiveLabs.Logging.Config.Configuration.DefaultLog = new FileLog(MainWindow.logFile, true);
            logger = LiveLabs.Logging.Config.Configuration.DefaultLog;
            try
            {
                //Properties.Settings.Default.ConnectionString = string.Empty;
                if (String.IsNullOrEmpty(Properties.Settings.Default.ConnectionString))
                {
                    string appDataFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\ProductKeyManager\";
                    if (!System.IO.Directory.Exists(appDataFolder))
                    {
                        System.IO.Directory.CreateDirectory(appDataFolder);
                    }
                    Properties.Settings.Default.ConnectionString = "Data Source=" + appDataFolder + MainWindow.dbFile;
                    Properties.Settings.Default.Save();
                    db = ProductKeyManagerDataContext.GetContext(Properties.Settings.Default.ConnectionString);
                    if (!db.DatabaseExists())
                    {
                        try
                        {
                            db.CreateDatabase();
                        }
                        catch (SqlCeException ex)
                        {
                            logger.WriteLine(string.Format("SqlCeException: {0} \r\n {1}", ex.Message, ex.StackTrace));
                            MessageBox.Show("Unable to create db file");
                        }
                    }
                }
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(WindowOnLoaded);
                this.Closing += new CancelEventHandler(Window_Closing);
            }
            catch (Exception ex)
            {
                logger.WriteLine(string.Format("Exception: {0} \r\n {1}", ex.Message, ex.StackTrace));
            }            
        }

        /// <summary>
        /// Windows the on loaded.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void WindowOnLoaded(object sender, RoutedEventArgs e)
        {
            try
            {
                LoadToolbarLocations();

                SetView();

                nameSort = ParseSortName(Properties.Settings.Default.SortNameDirection);
                OnNameSort(null, e);

                this.sldSearchLimit.ValueChanged += new RoutedPropertyChangedEventHandler<double>(sldSearchLimit_ValueChanged);

                if (Properties.Settings.Default.SaveLastSearch && !String.IsNullOrEmpty(Properties.Settings.Default.LastSearch))
                {
                    this.txtSearch.Text = Properties.Settings.Default.LastSearch;
                    chkSearch.IsChecked = true;
                    OnSearch(sender, e);
                }
            }
            catch (Exception ex)
            {
                logger.WriteLine(string.Format("Exception: {0} \r\n {1}", ex.Message, ex.StackTrace));
            }  
        }

        /// <summary>
        /// Loads the toolbar locations.
        /// </summary>
        private void LoadToolbarLocations()
        {
            toolAddEditDelete.Band = Properties.Settings.Default.AddEditDeleteBand;
            toolAddEditDelete.BandIndex = Properties.Settings.Default.AddEditDeleteBandIndex;

            toolSearch.Band = Properties.Settings.Default.SearchBand;
            toolSearch.BandIndex = Properties.Settings.Default.SearchBandIndex;

            toolTrayBottom.IsLocked = Properties.Settings.Default.LockToolBars;
            MenuViewLockToolBars.IsChecked = Properties.Settings.Default.LockToolBars;
        }

        /// <summary>
        /// Sets the view.
        /// </summary>
        private void SetView()
        {
            SaveToolbarLocations();

            if (db == null)
            {
                try
                {
                    db = ProductKeyManagerDataContext.GetContext(Properties.Settings.Default.ConnectionString);
                }
                catch (SqlCeException ex)
                {
                    logger.WriteLine(string.Format("SqlCeException: {0} \r\n {1}", ex.Message, ex.StackTrace));
                    MessageBox.Show("An error has occured connecting to the database");
                }
                catch (Exception ex)
                {
                    logger.WriteLine(string.Format("Exception: {0} \r\n {1}", ex.Message, ex.StackTrace));
                    throw;
                }
            }

            listProdKeys.DataContext = from p in db.Products.AsBindable()
                                       select p;

            SortAndSearch();
        }

        private ICollectionView GetProductView()
        {
            return CollectionViewSource.GetDefaultView(listProdKeys.DataContext);
        }

        private void SortAndSearch()
        {
            ICollectionView view = GetProductView();
            view.SortDescriptions.Clear();

            Product.SearchTerm = string.IsNullOrEmpty(searchText) ? string.Empty : searchText;

            if (string.IsNullOrEmpty(searchText))
            {
                view.Filter = null;
                switch (nameSort)
                {
                    case SortDirection.Ascending:
                        view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
                        break;
                    case SortDirection.Descending:
                        view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending));
                        break;
                    default:
                        break;
                }
            }
            else
            {
                this.lblSearchLimit.Content = String.Format(CultureInfo.CurrentCulture, "{0}% or more similarity", this.sldSearchLimit.Value * 100);
                if (view.Filter == null)
                {
                    view.Filter= delegate(object item)
                    {
                        return ((Product)item).SearchSimilarity >= ((decimal)this.sldSearchLimit.Value);
                    };
                }
            }
        }

        /// <summary>
        /// Saves the toolbar locations.
        /// </summary>
        private void SaveToolbarLocations()
        {
            Properties.Settings.Default.AddEditDeleteBand = toolAddEditDelete.Band;
            Properties.Settings.Default.AddEditDeleteBandIndex = toolAddEditDelete.BandIndex;

            Properties.Settings.Default.SearchBand = toolSearch.Band;
            Properties.Settings.Default.SearchBandIndex = toolSearch.BandIndex;

            Properties.Settings.Default.LockToolBars = toolTrayBottom.IsLocked;

            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Called when sorting by name.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void OnNameSort(object sender, RoutedEventArgs e)
        {
            MenuViewSortNameNone.IsChecked = false;
            MenuViewSortNameAsc.IsChecked = false;
            MenuViewSortNameDsc.IsChecked = false;
            if (sender != null)
            {
                nameSort = ParseSortName(((MenuItem)sender).Header.ToString());
            }
            switch (nameSort)
            {
                case SortDirection.None:
                    MenuViewSortNameNone.IsChecked = true;
                    break;
                case SortDirection.Ascending:
                    MenuViewSortNameAsc.IsChecked = true;
                    break;
                case SortDirection.Descending:
                    MenuViewSortNameDsc.IsChecked = true;
                    break;
            }
            SortAndSearch();
            Properties.Settings.Default.SortNameDirection = nameSort.ToString();
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Parses the name of the sort.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private static SortDirection ParseSortName(string name)
        {
            try
            {
                return (SortDirection)Enum.Parse(typeof(SortDirection), name, true);
            }
            catch (ArgumentException)
            {
                return SortDirection.None;
            }
        }

        /// <summary>
        /// Called on search.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void OnSearch(object sender, RoutedEventArgs e)
        {
            searchText = this.txtSearch.Text.ToLower(CultureInfo.CurrentCulture);
            Properties.Settings.Default.LastSearch = searchText;
            this.sldSearchLimit.Value = Properties.Settings.Default.DefaultSearchLimit;
            this.stkSearchLimit.Visibility = Visibility.Visible;
            SetView();
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Called when the search is cleared.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void OnUnSearch(object sender, RoutedEventArgs e)
        {
            searchText = null;
            Properties.Settings.Default.LastSearch = searchText;
            this.stkSearchLimit.Visibility = Visibility.Collapsed;
            SetView();
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Called when the New button is clicked
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void NewButtonClicked(object sender, RoutedEventArgs e)
        {
            ProductDialog newDlg = new ProductDialog();
            newDlg.Owner = this;
            newDlg.ShowDialog();
            newDlg.DB = db;

            SetView();
        }

        /// <summary>
        /// Called when the Edit button is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void EditButtonClicked(object sender, RoutedEventArgs e)
        {
            ProductDialog newDlg = new ProductDialog();
            newDlg.DB = db;
            newDlg.Mode = DialogMode.EditProduct;
            newDlg.Owner = this;
            newDlg.ProductId = ((Product)listProdKeys.SelectedItem).Id;
            newDlg.ShowDialog();

            SetView();
        }

        /// <summary>
        /// Called when the Delete button is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void DeleteButtonClicked(object sender, RoutedEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show(this, string.Format(CultureInfo.CurrentCulture, "Are you sure you want to delete'{0}'?",
                ((Product)listProdKeys.SelectedItem).Name) + " " + "This will remove the Product and all Keys permanently.", "Delete Product Key?",
                MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (result == MessageBoxResult.Yes)
            {
                foreach (ProductKeyManager.DB.Key k in (from key in db.Keys where key.ProductId == ((Product)listProdKeys.SelectedItem).Id select key))
                {
                    db.Keys.DeleteOnSubmit(k);
                    db.SubmitChanges();
                }
                db.Products.DeleteOnSubmit((Product)listProdKeys.SelectedItem);
                db.SubmitChanges();

                SetView();
            }
        }

        /// <summary>
        /// Called when the Exit menu item is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void FileMenuExitClicked(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Checks the database for a product.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="found">the product if found. (out)</param>
        /// <returns>Whether or not the product was found</returns>
        private bool DbHasProduct(Product entity, out Product found)
        {
            try
            {
                Product results = db.Products.Single(p => p.Name == entity.Name);
                found = results;
                return true;
            }
            catch (InvalidOperationException)
            {
                found = null;
                return false;
            }
        }

        /// <summary>
        /// Checks whether the product has a key
        /// </summary>
        /// <param name="prod">The product.</param>
        /// <param name="key">The key we are looking for</param>
        /// <returns>Whether or not the product has the key</returns>
        private static bool ProdHasKey(Product prod, ProductKeyManager.DB.Key key)
        {
            try
            {
                ProductKeyManager.DB.Key results = prod.Keys.Single(k => k.Code == key.Code && k.AllocatedTo == key.AllocatedTo);
                return results == null;
            }
            catch (InvalidOperationException)
            {
                return false;
            }
        }

        /// <summary>
        /// Merges the keys.
        /// </summary>
        /// <param name="importkeys">The importkeys.</param>
        private void MergeKeys(IEnumerable<Product> importkeys)
        {
            foreach (Product prod in importkeys)
            {
                Product found;
                if (DbHasProduct(prod, out found))
                {
                    foreach (ProductKeyManager.DB.Key key in prod.Keys)
                    {
                        if (!ProdHasKey(found, key))
                        {
                            found.Keys.Add(new ProductKeyManager.DB.Key { Code = key.Code, AllocatedTo = key.AllocatedTo });
                        }
                    }
                }
                else
                {
                    prod.UserName = Utility.UserInformation.CurrentUser();
                    db.Products.InsertOnSubmit(prod);
                }
            }
            db.SubmitChanges();
        }

        /// <summary>
        /// Called when the Import Products Key Manager Xml button is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void FileMenuImportProductKeyManagerXmlClicked(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog opendlg = new Microsoft.Win32.OpenFileDialog();
            opendlg.DefaultExt = "xml";
            opendlg.Filter = "Xml files (*.xml)|*.xml";
            if ((bool)opendlg.ShowDialog())
            {
                Mouse.OverrideCursor = Cursors.Wait;
                Xml.IXmlHandler handler = Xml.XmlHelper.ImportXml(new Uri(opendlg.FileName));
                if (handler.Products != null)
                {
                    MergeKeys(handler.Products);
                }
            }
            SetView();
            Mouse.OverrideCursor = Cursors.Arrow;
        }

        /// <summary>
        /// Called when the About button is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void MenuHelpAboutClicked(object sender, RoutedEventArgs e)
        {
            UI.AboutDialog helpWin = new UI.AboutDialog();
            helpWin.Owner = this;
            helpWin.ShowDialog();
        }

        /// <summary>
        /// Called when the Purge DB button is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ToolsPurgeDBClicked(object sender, RoutedEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show(this,
                "Are you sure you want to the contents of the PKM database? This will remove all Products and all Keys permanently.",
                "Delete Product Key?",
                    MessageBoxButton.YesNo, MessageBoxImage.Warning);
            if (result == MessageBoxResult.Yes)
            {
                db.Keys.DeleteAllOnSubmit(from k in db.Keys select k);
                db.SubmitChanges();
                db.Products.DeleteAllOnSubmit(from p in db.Products select p);
                db.SubmitChanges();
                SetView();
            }
        }

        /// <summary>
        /// Called on keypress in the search box. We are looking for either the return key or the escape key to 
        /// search or cancel search.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
        private void SearchKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Return)
            {
                chkSearch.IsChecked = !chkSearch.IsChecked;
                if ((bool)chkSearch.IsChecked)
                {
                    OnSearch(sender, null);
                }
                else
                {
                    OnUnSearch(sender, null);
                }
            }
            if (e.Key == System.Windows.Input.Key.Escape)
            {
                if ((bool)chkSearch.IsChecked)
                {
                    chkSearch.IsChecked = false;
                    OnUnSearch(sender, null);
                }
            }
        }

        /// <summary>
        /// Called on keypress in the product list box. We are looking for the delete key to delete selected keys.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
        private void ListBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Delete)
            {
                DeleteButtonClicked(sender, (RoutedEventArgs)e);
            }
        }

        /// <summary>
        /// Handles the SelectionChanged event of the listProdKeys control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        private void listProdKeys_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                bool isSelected = false;
                if (listProdKeys.SelectedIndex > -1)
                {
                    isSelected = true;
                }

                MenuEdit.IsEnabled = isSelected;
                toolbEdit.IsEnabled = isSelected;
            }
            catch (Exception ex)
            {
                logger.WriteLine(string.Format("Exception: {0} \r\n {1}", ex.Message, ex.StackTrace));
            }
        }

        /// <summary>
        /// Handles the DoubleClicked event of the listProdKeys control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void listProdKeys_DoubleClicked(object sender, RoutedEventArgs e)
        {
            if (listProdKeys.SelectedIndex > -1)
            {
                ProductDialog viewWindow = new ProductDialog();
                viewWindow.Mode = DialogMode.ViewProduct;
                viewWindow.ProductId = ((Product)listProdKeys.SelectedItem).Id;
                viewWindow.Owner = this;
                viewWindow.ShowDialog();
            }
        }

        private void FileMenuExportXmlClicked(object sender, RoutedEventArgs e)
        {
            bool GenerateStyleSheet = false;
            Microsoft.Win32.SaveFileDialog save = new Microsoft.Win32.SaveFileDialog();
            if (((MenuItem)sender).Name == "MenuFileExportXAML")
            {
                save.DefaultExt = "xaml";
                save.Filter = "XAML files (*.xaml)|*.xaml";
            }
            else
            {
                GenerateStyleSheet = PromptExportXsl();
                save.DefaultExt = "xml";
                save.Filter = "Xml files (*.xml)|*.xml";
            }

            if (((MenuItem)sender).Name == "MenuFileExportXAML")
            {
                MessageBox.Show("At this time XAML format exports cannot be imported. The PKM format should be used for backups.");
                if ((bool)save.ShowDialog())
                {
                    Mouse.OverrideCursor = Cursors.Wait;

                    Xml.IXmlHandler handler = new Xml.XamlHandler();

                    IEnumerable<Product> products = (IEnumerable<Product>)this.listProdKeys.DataContext;
                    handler.GenerateXml(products);

                    Xml.XmlHelper.SaveProductKeyXml(GenerateStyleSheet, save.FileName, handler.GeneratedXml, string.Empty);
                    Mouse.OverrideCursor = Cursors.Arrow;
                }
            }
            else
            {
                if ((bool)save.ShowDialog())
                {
                    Mouse.OverrideCursor = Cursors.Wait;
                    string styleSheet = "";

                    Xml.IXmlHandler handler = null;
                    if (((MenuItem)sender).Name == "MenuFileExportPKM")
                    {
                        handler = new Xml.ProductKeyManagerXmlHandler();
                        styleSheet = Properties.Settings.Default.ProductKeyManagerXmlStylesheet;
                    }
                    else
                    {
                        handler = new Xml.MsdnXmlHandler();
                        styleSheet = Properties.Settings.Default.MsdnXmlStyleSheet;
                    }
                    IEnumerable<Product> products = (IEnumerable<Product>)this.listProdKeys.DataContext;
                    handler.GenerateXml(products, GenerateStyleSheet, save.FileName);
                    styleSheet = styleSheet.Replace("\"\"", "\"");
                    
                    Xml.XmlHelper.SaveProductKeyXml(GenerateStyleSheet, save.FileName, handler.GeneratedXml, styleSheet);
                }
                Mouse.OverrideCursor = Cursors.Arrow;
            }
        }

        /// <summary>
        /// Prompts the export XSL.
        /// </summary>
        /// <returns></returns>
        private static bool PromptExportXsl()
        {
            bool GenerateStyleSheet = false;
            if (Properties.Settings.Default.EnableXslExport && Properties.Settings.Default.PromptXsl)
            {
                GenerateStyleSheet = MessageBox.Show("Would you like a XSL stylesheet generated? This will make the results easier to view results when opened in some applications such as Internet Explorer and FireFox.", "Generate Stylesheet?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes;
            }
            else if (Properties.Settings.Default.EnableXslExport && !Properties.Settings.Default.PromptXsl)
            {
                GenerateStyleSheet = true;
            }
            else
            {
                GenerateStyleSheet = false;
            }
            return GenerateStyleSheet;
        }

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            db.Dispose();
        }

        #endregion

        /// <summary>
        /// Handles the Closing event of the Window control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
        private void Window_Closing(object sender, CancelEventArgs e)
        {
            SaveToolbarLocations();
        }

        /// <summary>
        /// Handles the Click event of the LockToolBars control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void LockToolBars_Click(object sender, RoutedEventArgs e)
        {
            bool isLocked = ((MenuItem)sender).IsChecked;
            this.toolTrayBottom.IsLocked = isLocked;
        }

        /// <summary>
        /// Handles the Click event of the ToolsSettings control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ToolsSettings_Click(object sender, RoutedEventArgs e)
        {
            Settings settingsWindow = new Settings();
            settingsWindow.Owner = this;
            settingsWindow.ShowDialog();
            LoadToolbarLocations();
            SetView();
        }

        private void sldSearchLimit_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            try
            {
                if (listProdKeys.DataContext != null)
                {
                    SortAndSearch();
                }
            }
            catch (Exception ex)
            {
                logger.WriteLine(string.Format("Exception: {0} \r\n {1}", ex.Message, ex.StackTrace));
            }
        }
    }
}